package com.winit.openapi.interceptor;

import java.util.HashSet;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.winit.ac.RateLimiter;
import com.winit.ac.RateLimiter.Permits;
import com.winit.ac.impl.RedisRateLimiter.RedisRateLimiterBuilder;
import com.winit.common.spi.context.CommandContext;
import com.winit.erp.spi.user.vo.User;
import com.winit.openapi.apiadapter.adapter.UmsUserServiceAdapter;
import com.winit.openapi.constants.ApiConstant;
import com.winit.openapi.constants.ErrorCode;
import com.winit.openapi.exception.ApiException;
import com.winit.openapi.model.RequestMsg;
import com.winit.openapi.upush2.sender.APIMonitoringEmailSender;
import com.winit.openapi.util.APISysConfigUtil;
import com.winit.openapi.util.RequestUtil;

/**
 * 访问频率拦截器
 * 
 * @version Revision History
 * 
 * <pre>
 * Author     Version       Date        Changes
 * kang.wang    1.0           2014-10-24     Created
 * 
 * </pre>
 * @since 1.
 */
public class AccessFrequencyInterceptor implements InitializingBean, HandlerInterceptor {

    private static final Logger      logger       = LoggerFactory.getLogger(AccessFrequencyInterceptor.class);

    @Resource
    private APIMonitoringEmailSender emailSender;

    @Resource
    private APISysConfigUtil         apiSysConfigUtil;

    @Resource
    private UmsUserServiceAdapter    umsUserServiceAdapter;
    // @Resource
    // private Config config;
    /**
     * API访问频率控制器
     */
    private RateLimiter              rateLimiter;
    /**
     * 不需要强制限制调用次数的账号
     */
    private static Set<String>       no_check_set = new HashSet<String>();

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object obj,
                                Exception exception) throws Exception {
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object obj,
                           ModelAndView modelandview) throws Exception {
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) throws Exception {
        RequestMsg requestMsg = RequestUtil.getRequestMsg(request);

        String platform = requestMsg.getPlatform();
        // 过滤掉来自卖家网站的流量
        if (("sw").equalsIgnoreCase(platform) || ("seller").equalsIgnoreCase(platform)
            || ("SW-B").equalsIgnoreCase(platform) || ("SW-S").equalsIgnoreCase(platform)) {

            return true;

        }
        CommandContext ctx = CommandContext.getContext();

        Permits permits = null;
        String appkey = ctx.get(ApiConstant.API_APP_KEY) == null ? requestMsg.getApp_key() : ctx.get(ApiConstant.API_APP_KEY)
            .toString();
        if (appkey == null || no_check_set.contains(appkey)) {
            return true;
        }
        
        User user = umsUserServiceAdapter.queryUserByNameAndPlatform(appkey, requestMsg.getPlatform());
        if (user == null || user.getFrequency() == null || user.getFrequency().longValue() == 0) {
            String defaultLimitCount = apiSysConfigUtil.getConfigValueByKey("API_FREQUENCY_COUNT_PER_UNIT");
            int defaultCount = StringUtils.isBlank(defaultLimitCount) ? 1000 : Integer.valueOf(defaultLimitCount);
            logger.warn("获取用户访问频率失败，使用默认频率:" + defaultLimitCount + " 用户:" + appkey);
            permits = rateLimiter.isPermits(appkey, defaultCount);
        } else {
            permits = rateLimiter.isPermits(appkey, user.getFrequency().intValue());
        }
        boolean hasPermits = permits.isHasPermits();

        ctx.set(ApiConstant.API_FREQUENCY_PER_UNIT, permits.getNowAccessTimes());
        if (!hasPermits) {
            // 不在白名单里面的抛异常
            if (!no_check_set.contains(appkey)) {
                // 超过频率限制抛异常，发告警邮件
                if (user != null) {
                    emailSender.checkAndSendEmail(appkey, permits.getNowAccessTimes(), user.getFrequency().intValue());
                }
                throw new ApiException(ErrorCode.ACCESS_DELY);
            }
        }

        return true;
    }

    @Override
    public void afterPropertiesSet() throws Exception {

        String interval = apiSysConfigUtil.getConfigValueByKey("API_FREQUENCY_INTERVAL_UNIT");
        String limitCount = apiSysConfigUtil.getConfigValueByKey("API_FREQUENCY_COUNT_PER_UNIT");
        String limitWhiteList = apiSysConfigUtil.getConfigValueByKey("API_FREQUENCY_LIMIT_WHITELIST");

        rateLimiter = new RedisRateLimiterBuilder().timeUnit(Integer.valueOf(interval))
            .permitsPerTimeUnit(Integer.valueOf(limitCount))
            .localPermitsPercent(1f)
            .build();

        initWhiteList(limitWhiteList);
        logger.info("加载API频率白名单完成：" + no_check_set);

    }

    private void initWhiteList(String whiteListString) {
        // String whiteListString = config.getLimitWhite();
        if (StringUtils.isNotBlank(whiteListString)) {
            String[] list = whiteListString.split(",");
            if (list != null && list.length > 0) {
                for (String appKey : list) {
                    if (StringUtils.isNotBlank(appKey)) {
                        no_check_set.add(appKey.trim());
                    }
                }

            }
        }
    }

}
